﻿#include "world.h"


World::World(void)
{
}


World::~World(void)
{

}


void World::RenderCallBack(LPVOID param) {
  World* This = (World*)param;
  This->ExecuteRender();
}


void World::ControlCallBack(LPVOID param) {
  World* This = (World*)param;
  This->ExecuteControl();
}

void World::ThreadControlCallBack(LPVOID param) {
  World* This = (World*)param;
  This->ExecuteControlThread();
}


void World::ThreadCollisionCallBack(LPVOID param) {
  World* This = (World*)param;
  This->ExecuteCollisionThread();
}


void World::ThreadEventCallBack(LPVOID param) {
  World* This = (World*)param;
  This->ExecuteEventThread();;
}


int World::Init(HINSTANCE hInstance ,HWND hWnd) {
  
  /* Init world variable */

  this->worldIsDestroy = false;
  this->hInstance = hInstance;
  this->hWnd = hWnd;

  /* Init static member */

  Path::Init();
  Log::InitStatic();

  /* Init game base object */

  // Init screen, direct 3d
  bool initDirect3d = this->screen.Init(hWnd); // init screen instance
  // Init audio system
  audio.Init(hWnd);
  // Init control system
  bool initControl = control.Init(this->hInstance, this->hWnd);
  // Init log system
  log.Init(&screen);

  /* Check init result */

  if((initDirect3d & initControl) == false) {
    MessageBox(hWnd, INIT_ERROR_TEXT, EXIT_CONFIRM_CAPTION, MB_OK); 
    return 1;
  } else {

    /* Load map, init game objects */

    map.Load(L"C:\\map.map");

    return 0;
  }

}


int World::ExecuteRender() {

  /* Init render variable */

  LPDIRECT3DDEVICE9 d3ddev = screen.getDevive();
  LPDIRECT3DSURFACE9 surface = screen.getSurface();
  LPDIRECT3DSURFACE9 backBuffer = screen.getBackBuffer();
  D3DXCOLOR backColor = map.getBackColor();
  /* Render loop */ 

  while(this->worldIsDestroy == false) {
    if (screen.WillPrintNextFrame() == true) {
      d3ddev->Clear(0,
                  NULL,
                  D3DCLEAR_TARGET, 
                  backColor, // blue
                  1.0f,
                  0);
    // start render
    if (d3ddev->BeginScene()) {
      
      /* Draw game objects */ 
      this->renderManager.Renders();

      // Write log
      //
      log.Render();
     
      // End render
      //
      d3ddev->EndScene();
    }
    // Display backbuffer to the screen
    d3ddev->Present(NULL, NULL, NULL, NULL);
    }
  }
  return 0;
}


int World::ExecuteControl() {
  while(this->worldIsDestroy == false) {
    control.CatchEvent();
    Sleep(1); // sleep for 1 ms
  }
  return 0;
}


int World::ExecuteControlThread() {
    while(this->worldIsDestroy == false) {
      this->controlManager.Threading();
    Sleep(1); // sleep for 1 ms
  }
  return 0;
}


int World::ExecuteCollisionThread() {
  while(this->worldIsDestroy == false) {
      this->collisionManager.Threading();
    Sleep(1); // sleep for 1 ms
  }
  return 0;
}


int World::ExecuteEventThread() {
  while(this->worldIsDestroy == false) {
    this->eventManager.Threading();
    Sleep(1); // sleep for 1 ms
  }
  return 0;
}


void World::Exeute() {
  // Render
  this->handleRender = CreateThread(
      NULL, NULL, (LPTHREAD_START_ROUTINE)RenderCallBack,
      (LPVOID)this, 0, NULL);
  // Control
  this->handleControl = CreateThread(
      NULL, NULL, (LPTHREAD_START_ROUTINE)ControlCallBack,
      (LPVOID)this, 0, NULL);
  // Control thead callback
  this->handleControlThread =  CreateThread(
      NULL, NULL, (LPTHREAD_START_ROUTINE)ThreadControlCallBack,
      (LPVOID)this, 0, NULL);
  // Collision thread call back
  this->handleCollisionThread = CreateThread(
      NULL, NULL, (LPTHREAD_START_ROUTINE)ThreadCollisionCallBack,
      (LPVOID)this, 0, NULL);
  // Event thread call back
  this->handleEventThread = CreateThread(
      NULL, NULL, (LPTHREAD_START_ROUTINE)ThreadEventCallBack,
      (LPVOID)this, 0, NULL);
}


void World::End() {
  // Release control
  // destroy world
  this->worldIsDestroy = true;
  // release static variable in path
  Path::Release();
  
  /* waiting all thread exit */

  Sleep(100);
  LPDWORD exitCode = new DWORD;
  // Render thread
  *exitCode = 1;
  do {
    GetExitCodeThread(this->handleRender, exitCode);
     Sleep(1);
  } while (*exitCode != 0);
  // Control thread
  *exitCode = 1;
  do {
    GetExitCodeThread(this->handleControl, exitCode);
     Sleep(1);
  } while (*exitCode != 0);
  // Control callback thread
  *exitCode = 1;
  do {
    GetExitCodeThread(this->handleControlThread, exitCode);
     Sleep(1);
  } while (*exitCode != 0);
  // Collision callback thread
  *exitCode = 1;
  do {
    GetExitCodeThread(this->handleCollisionThread, exitCode);
     Sleep(1);
  } while (*exitCode != 0);
  // Event callback thread
  *exitCode = 1;
  do {
    GetExitCodeThread(this->handleEventThread, exitCode);
     Sleep(1);
  } while (*exitCode != 0);
  delete exitCode;
  
  // Release game objects
  this->objectsManager.Releases();
  // Release texture
  this->texturesManager.RemoveAll();
}
